import * as _ from 'lodash';
import * as path from 'path';

import { Storage } from '$infra';
import { Parameter } from '$common';
import { StoragePath } from '../simulationStoragePath';
import { SimulationPath } from '../simulationPath';
import { OutputParameter } from '$domain/model/driver';
import { SimulationLogger } from '../simulationLogger';
import { ParameterType, SimulationParameter } from '../type';

export class SimulationParameterService {

  constructor(private logger: SimulationLogger, private storagePath: StoragePath, private simulationPath: SimulationPath) { }

  leftMergeParameters<T extends Parameter>(leftParameters: T[], rightParameters: T[]) {
    if (_.isEmpty(rightParameters)) { return leftParameters; }
  
    return leftParameters.reduce((result, left) => {
      const sameItem = rightParameters.find(right => right.name === left.name );
  
      if (_.isEmpty(sameItem)) {
        result.push(left);
      } else {
        result.push(Object.assign({}, left, sameItem));
      }
  
      return result;
    }, []);
  }

  uploadFileParameters = async (fileParameters: OutputParameter[] = []) => {
    if (_.isEmpty(fileParameters)) { return []; }
    
    return await Promise.all(
      fileParameters
        .map(async (fileParameter) => {
          const localFilePath = fileParameter.value;

          const prefixObjectName = this.storagePath.getSimResultPath();
          const suffixObjectName = _.last(localFilePath.split(path.sep));

          const objectName = `${prefixObjectName}/${suffixObjectName}`;
          this.logger.debug(`✅ uploading parameter: ${fileParameter.name} result file from ${localFilePath} to ${objectName}`);
          await Storage.Instance.fPutObject(objectName, localFilePath);

          fileParameter.value = objectName;
          return fileParameter;
        }));
  }

  downloadFileParameters = async (fileParameters: SimulationParameter[] = []): Promise<SimulationParameter[]> => {
    if (_.isEmpty(fileParameters)) { return []; }

    return await Promise.all(fileParameters?.map(async (fileParameter) => {
      const objectName: string = fileParameter.value;

      const parameterFilename = fileParameter.name.replace(" ", "_") + "_" + _.last(objectName.split('/'));
      const parameterFilePath = this.simulationPath.getParameterFile(parameterFilename);

      this.logger.debug(`🌈 download parameter file from ${objectName} to ${parameterFilePath}`);
      await Storage.Instance.fGetObject(objectName, parameterFilePath);
      fileParameter.value = parameterFilePath;
      return fileParameter;
    }));
  }

  transformOutputParameters = async (outputParametes: OutputParameter[] = []) => {
    if (_.isEmpty(outputParametes)) { return outputParametes; }
    
    const fileParameters = outputParametes.filter(f => { return _.includes([ParameterType.FILE, ParameterType.CSV, ParameterType.XLSX, ParameterType.ZIP], f.type); });
    const uploadedParameters = await this.uploadFileParameters(fileParameters);
    return this.leftMergeParameters<OutputParameter>(outputParametes, uploadedParameters);
  }
}